// FSFolder.h

#ifndef __FSFOLDER_H
#define __FSFOLDER_H

#include "Common/FileSystem/FileFind.h"

#include "IFolder.h"
#include "Common/String/TextPairs.h"

#include <atlbase.h>

#include <memory>
#include <deque>

namespace Common {
namespace FileSystem {

namespace Folder {

class CFSFolder;

struct CFileInfoEx: public Common::FileSystem::File::CFileInfo
{
  bool		CompressedSizeIsDefined;
  UINT64	CompressedSize;
  CFileInfoEx() {}
  CFileInfoEx(const CFileInfoEx & obj) :
	  CFileInfo(obj),
	  CompressedSizeIsDefined(obj.CompressedSizeIsDefined),
	  CompressedSize(obj.CompressedSize)
  {

  }
};

struct CDirItem;

struct CDirItem: public CFileInfoEx
{
	typedef std::shared_ptr<CDirItem> PtrDirItem;
	typedef std::deque<PtrDirItem> ArrayPtrDirItem;
	PtrDirItem Parent;
	ArrayPtrDirItem Files;

  CDirItem(): Parent(0) {}
  void Clear()
  {
    Files.clear();
    Parent = 0;
  }
};

class ATL_NO_VTABLE CFSFolder:
  public IFolderFolder,
  public IFolderWasChanged,
  public IFolderOperations,
  // public IFolderOperationsDeleteToRecycleBin,
  public IFolderGetItemFullSize,
  public IFolderClone,
  public IFolderGetSystemIconIndex,
  public IFolderSetFlatMode,
  public CComObjectRootEx<CComSingleThreadModel>  
{
  UINT64 GetSizeOfItem(int anIndex) const;
public:
  
	BEGIN_COM_MAP(CFSFolder)
		COM_INTERFACE_ENTRY(IFolderFolder)
		COM_INTERFACE_ENTRY(IFolderWasChanged)
		COM_INTERFACE_ENTRY(IFolderOperations)
		COM_INTERFACE_ENTRY(IFolderGetItemFullSize)
		COM_INTERFACE_ENTRY(IFolderClone)
		COM_INTERFACE_ENTRY(IFolderGetSystemIconIndex)
		COM_INTERFACE_ENTRY(IFolderSetFlatMode)
	END_COM_MAP()



	DECLARE_PROTECT_FINAL_CONSTRUCT()

	HRESULT FinalConstruct()
	{		
		_root = std::make_shared<CDirItem>();
		return S_OK;
	}

	void FinalRelease()
	{

	}

	//INTERFACE FolderFolder
	STDMETHOD(LoadItems)() ;
	STDMETHOD(GetNumberOfItems)(UINT32 *numItems) ;
	STDMETHOD(GetProperty)(UINT32 itemIndex, PROPID propID, PROPVARIANT *value) ;
	STDMETHOD(BindToFolder)(UINT32 index, IFolderFolder **resultFolder) ;
	STDMETHOD(BindToFolder)(const wchar_t *name, IFolderFolder **resultFolder) ;
	STDMETHOD(BindToParentFolder)(IFolderFolder **resultFolder) ;
	STDMETHOD(GetNumberOfProperties)(UINT32 *numProperties) ;
	STDMETHOD(GetPropertyInfo)(UINT32 index, BSTR *name, PROPID *propID, VARTYPE *varType) ;
	STDMETHOD(GetFolderProperty)(PROPID propID, PROPVARIANT *value) ;

	//INTERFACE FolderOperations
	STDMETHOD(CreateFolder)(const wchar_t *name, IProgress *progress) ;
	STDMETHOD(CreateFile)(const wchar_t *name, IProgress *progress) ;
	STDMETHOD(Rename)(UINT32 index, const wchar_t *newName, IProgress *progress) ;
	STDMETHOD(Delete)(const UINT32 *indices, UINT32 numItems, IProgress *progress) ;
	STDMETHOD(CopyTo)(const UINT32 *indices, UINT32 numItems, 
      const wchar_t *path, IFolderOperationsExtractCallback *callback) ;
	STDMETHOD(MoveTo)(const UINT32 *indices, UINT32 numItems, 
      const wchar_t *path, IFolderOperationsExtractCallback *callback) ;
	STDMETHOD(CopyFrom)(const wchar_t *fromFolderPath, 
      const wchar_t **itemsPaths, UINT32 numItems, IProgress *progress) ;
	STDMETHOD(SetProperty)(UINT32 index, PROPID propID, const PROPVARIANT *value, IProgress *progress) ;

  STDMETHOD(WasChanged)(INT32 *wasChanged);
  STDMETHOD(Clone)(IFolderFolder **resultFolder);
  STDMETHOD(GetItemFullSize)(UINT32 index, PROPVARIANT *value, IProgress *progress);

  STDMETHOD(SetFlatMode)(INT32 flatMode);

  STDMETHOD(GetSystemIconIndex)(UINT32 index, INT32 *iconIndex);

private:
  CString _path;
  std::shared_ptr<CDirItem> _root;
  CDirItem::ArrayPtrDirItem _refs;

  CComPtr<IFolderFolder> _parentFolder;

  bool _commentsAreLoaded;
  String::CPairsStorage _comments;

  bool _flatMode;

  Common::FileSystem::Find::CFindChangeNotification _findChangeNotification;

  HRESULT GetItemsFullSize(const UINT32 *indices, UINT32 numItems,
      UINT64 &numFolders, UINT64 &numFiles, UINT64 &size, IProgress *progress);
  HRESULT GetItemFullSize(int index, UINT64 &size, IProgress *progress);
  HRESULT GetComplexName(const wchar_t *name, CString &resultPath);
  HRESULT BindToFolderSpec(const wchar_t *name, IFolderFolder **resultFolder);

  bool LoadComments();
  bool SaveComments();
  HRESULT LoadSubItems(std::shared_ptr<CDirItem> &dirItem, const CString &path);
  void AddRefs(CDirItem::PtrDirItem & dirItem);
public:
  HRESULT Init(const CString &path, IFolderFolder *parentFolder);  

  CFSFolder() : _flatMode(false) {}

  CString GetPrefix(const CDirItem &item) const;
  CString GetRelPath(const CDirItem &item) const;
  CString GetRelPath(UINT32 index) const { return GetRelPath(*_refs[index]); }

  void Clear()
  {
	  if(NULL != _root.get())
		_root->Clear();
    _refs.clear();
  }
};

HRESULT GetFolderSize(const CString &path, UINT64 &numFolders, UINT64 &numFiles, UINT64 &size, IProgress *progress);

}
}
}

#endif
